﻿using QuizServicesAzure.BL;
using QuizServicesAzure.DAL;
using QuizServicesAzure.Entity;
using QuizServicesAzure.Requests;
using QuizServicesAzure.Responses;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuizServicesAzure
{
    // NOTA: è possibile utilizzare il comando "Rinomina" del menu "Refactoring" per modificare il nome di classe "Service1" nel codice, nel file svc e nel file di configurazione contemporaneamente.
    // NOTA: per avviare il client di prova WCF per testare il servizio, selezionare Service1.svc o Service1.svc.cs in Esplora soluzioni e avviare il debug.
    public class QuizService : IQuizService
    {
        private static InfosQuizDBEntities Db { get; set; }

        public GetTipologieAndDifficoltaResponse GetTipologieAndDifficolta(GetTipologieAndDifficoltaRequest request)
        {
            CreateDBConnetion();

            GetTipologieAndDifficoltaResponse response = new GetTipologieAndDifficoltaResponse();

            var listDiff = Db.Difficolta.OrderBy(x => x.IDDifficolta);
            response.ListDifficolta =
             (from elemento in listDiff
              select new DifficoltaService()
              {
                  IDDifficolta = elemento.IDDifficolta,
                  NumMaxDomande = elemento.NumMaxDomande,
                  TempoMaxDomande = elemento.TempoMaxDomande,
                  Punteggio = elemento.Punteggio,
                  Titolo = elemento.Titolo,
              }).ToArray();


            var listTip = Db.TipologiaTest.OrderBy(x => x.Descrizione);

            response.ListTipologie =
            (from elemento in listTip
             select new TipologiaTestService()
             {
                 Descrizione = elemento.Descrizione,
                 DataCreazione = elemento.DataCreazione,
                 IdTipologiaTest = elemento.IdTipologiaTest,
                 Aggiornamenti = Db.Domande.Any(x => x.IdTipologiaTest == elemento.IdTipologiaTest && x.Version > request.Version)
             }).ToArray();


            response.UpdateDifficolta = Db.Difficolta.Where(x => x.Versione > request.Version).Count();
            response.UpdateDomande = Db.Domande.Where(x => x.Version > request.Version).Count();
            response.UpdateTipologie = Db.TipologiaTest.Where(x => x.Version > request.Version).Count();
            response.Version = Db.Version.Single().IDVersion;
            response.InfoBacheca = Db.Bacheca.Single().Informativa;

            return response;

        }

        /// <summary>
        /// Metodo Utilizzato
        /// </summary>
        private void CreateDBConnetion()
        {
            Db = (Db == null) ? new InfosQuizDBEntities() : Db;
        }

        public GetAllDomandeByTipologiaTestResponse GetAllDomandeByTipologiaTest(GetAllDomandeByTipologiaTestRequest request)
        {
            CreateDBConnetion();
            var list = Db.Domande.Where(c => c.IdTipologiaTest == request.idTipologiaTest);
            var listaDomandeService =
                (from elemento in list
                 select new DomandaService()
                 {
                     IdDomanda = elemento.IdDomanda,
                     Domanda = elemento.Domanda,
                     IdTipologiaTest = (long)elemento.IdTipologiaTest
                 }).ToArray();
            return new GetAllDomandeByTipologiaTestResponse() { response = listaDomandeService };
        }

        /// <summary>
        /// Metodo che elabora costruisce un questionario in relazione alla tipologia di test e alla difficoltà
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public GetAllQuestionarioResponse GetAllQuestionario(GetAllQuestionarioRequest request)
        {
            try
            {
                CreateDBConnetion();
                var Dif = Db.Difficolta.Where(x => x.IDDifficolta == request.IdDifficolta).Single();
                var filtrolista = Db.Domande.Where(x => x.IdTipologiaTest == request.idTipologiaTest && x.isVisibile == true).ToList();
                var listaDomande = (from elemento in Filtro<Domande>.FiltraDifficolta(filtrolista, Dif.NumMaxDomande)
                                    select new DomandaService()
                                    {
                                        Domanda = elemento.Domanda,
                                        IdDomanda = elemento.IdDomanda,
                                        IdTipologiaTest = elemento.IdTipologiaTest,
                                        PossibiliRisposte =
                                        (from posRisp in Filtro<PossibiliRisposte>.FiltraAndMescolaRisposte(elemento.PossibiliRisposte.ToList(), elemento.PossibiliRisposte.Count())
                                         select new PossibiliRisposteService()
                                         {
                                             DescrizioneRisposta = posRisp.DescrizioneRisposta,
                                             IdDomanda = posRisp.IdDomanda,
                                             IdPossibileRisposta = posRisp.IdPossibileRisposta,
                                             IsCorretta = posRisp.IsCorretta
                                         }).ToArray()

                                    }).ToArray();
                var response = new GetAllQuestionarioResponse();
                response.Difficolta = new DifficoltaService()
                {
                    IDDifficolta = Dif.IDDifficolta,
                    NumMaxDomande = Dif.NumMaxDomande,
                    TempoMaxDomande = Dif.TempoMaxDomande,
                    Titolo = Dif.Titolo
                };
                response.Questionario.ListaDomande = listaDomande;
                response.Questionario.NomeQuestionario = Db.TipologiaTest.Where(x => x.IdTipologiaTest == request.idTipologiaTest).Single().Descrizione;
                return response;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public GetListPunteggioResponse GetListPunteggio(GetListPunteggioRequest request)
        {
            try
            {
                CreateDBConnetion();
                var ListElement = Db.Punteggi.OrderByDescending(x => x.Punteggio).Take(10).ToList();
                var esito = new GetListPunteggioResponse()
                {
                    ListPunteggi =
                    (from p in ListElement
                     select new PunteggioService()
                     {
                         Index = ListElement.IndexOf(p) + 1,
                         IdDifficolta = (int)p.IdDifficolta,
                         IdPunteggio = p.IdPunteggio,
                         IdTipologiaTest = (int)p.IdTipologiaTest,
                         Punteggio = (long)p.Punteggio,
                         UserName = p.Account,
                         TipologiaTest = p.TipologiaTest.Descrizione,
                         Moltiplicatore = p.Moltiplicatore
                     }).ToArray()
                };
                return esito;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public GetAllListPunteggiResponse GetAllListPunteggi(GetListPunteggioRequest request)
        {
            try
            {
                CreateDBConnetion();
                var listaTipologie = Db.TipologiaTest.OrderBy(x => x.Descrizione).ToList();
                List<GetListPunteggioResponse> listAllPunteggi = new List<GetListPunteggioResponse>();
                foreach (var singleTipologia in listaTipologie)
                {
                    var ListElement = Db.Punteggi.Where(x => x.IdTipologiaTest == singleTipologia.IdTipologiaTest).OrderByDescending(x => x.Punteggio).Take(10).ToList();
                    var esito = new GetListPunteggioResponse()
                    {
                        ListPunteggi =
                        (from p in ListElement
                         select new PunteggioService()
                         {
                             Index = ListElement.IndexOf(p) + 1,
                             IdDifficolta = (int)p.IdDifficolta,
                             IdPunteggio = p.IdPunteggio,
                             IdTipologiaTest = (int)p.IdTipologiaTest,
                             Punteggio = (long)p.Punteggio,
                             UserName = p.Account,
                             TipologiaTest = p.TipologiaTest.Descrizione,
                             SecondiRimanenti = (int)p.SecondiRimanenti,
                             Moltiplicatore = p.Moltiplicatore
                         }).ToArray()
                    };
                    listAllPunteggi.Add(esito);
                }
                return new GetAllListPunteggiResponse() { ListAllPunteggi = listAllPunteggi.ToArray() };
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public GetAllListPunteggiResponse GetAllListPunteggiByDifficolta(short IdDifficolta)
        {
            try
            {
                CreateDBConnetion();
                var listaTipologie = Db.TipologiaTest.OrderBy(x => x.Descrizione).ToList();
                List<GetListPunteggioResponse> listAllPunteggi = new List<GetListPunteggioResponse>();
                foreach (var singleTipologia in listaTipologie)
                {
                    List<Punteggi> ListElement = new List<Punteggi>();
                    if (IdDifficolta > 0)
                        ListElement = Db.Punteggi
                                            .Where(x => x.IdTipologiaTest == singleTipologia.IdTipologiaTest && x.IdDifficolta == (int)(IdDifficolta))
                                            .OrderByDescending(x => x.Punteggio)
                                            .Take(10)
                                            .ToList();
                    else
                        ListElement = Db.Punteggi
                                            .Where(x => x.IdTipologiaTest == singleTipologia.IdTipologiaTest)
                                            .OrderByDescending(x => x.Punteggio)
                                            .Take(10)
                                            .ToList();
                    var esito = new GetListPunteggioResponse()
                    {
                        ListPunteggi =
                        (from p in ListElement
                         select new PunteggioService()
                         {
                             Index = ListElement.IndexOf(p) + 1,
                             IdDifficolta = (int)p.IdDifficolta,
                             IdPunteggio = p.IdPunteggio,
                             IdTipologiaTest = (int)p.IdTipologiaTest,
                             Punteggio = (long)p.Punteggio,
                             UserName = p.Account,
                             TipologiaTest = p.TipologiaTest.Descrizione,
                             SecondiRimanenti = (int)p.SecondiRimanenti,
                             Moltiplicatore = p.Moltiplicatore
                         }).ToArray()
                    };
                    listAllPunteggi.Add(esito);
                }
                return new GetAllListPunteggiResponse() { ListAllPunteggi = listAllPunteggi.ToArray() };
            }
            catch (Exception ex)
            {
                throw;
            }
        }





        #region Vecchi Contratti

        public SetPunteggioResponse SetPunteggio(SetPunteggioRequest request)
        {
            try
            {
                if (request.Username == "")
                    request.Username = "Anonymous";
                CreateDBConnetion();
                Punteggi punt = new Punteggi()
                {
                    IdDifficolta = request.IdDifficolta,
                    IdTipologiaTest = request.IdTipologiaTest,
                    Punteggio = request.Punteggio,
                    Account = request.Username,
                    Moltiplicatore = request.Moltiplicatore,
                    SecondiRimanenti = (request.SecondiRimanenti == null) ? 0 : request.SecondiRimanenti,
                };
                var PunteggioInserito = Db.Punteggi.Add(punt);
                Db.SaveChanges();
                var esito = new SetPunteggioResponse();

                if (Db.Punteggi.Where(x => x.IdTipologiaTest == punt.IdTipologiaTest).OrderByDescending(x => x.Punteggio).Take(10).ToList().Contains(PunteggioInserito))
                    esito.isClassifica = true;

                esito.PunteggioAggiornato = new PunteggioService()
                {
                    IdDifficolta = (int)PunteggioInserito.IdDifficolta,
                    IdPunteggio = PunteggioInserito.IdPunteggio,
                    IdTipologiaTest = (int)PunteggioInserito.IdTipologiaTest,
                    Punteggio = (long)PunteggioInserito.Punteggio
                };
                return esito;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        #endregion

        #region Nuovi Contratti

        public SetPunteggioResponse SetPunteggioV2(SetPunteggioNewRequest request)
        {
            try
            {
                PunteggioService req = request.Request;
                if (req.UserName == "")
                    req.UserName = "Utente Non Registrato";
                CreateDBConnetion();
                Punteggi punt = new Punteggi()
                {
                    IdDifficolta = req.IdDifficolta,
                    IdTipologiaTest = req.IdTipologiaTest,
                    Punteggio = req.Punteggio,
                    Account = req.UserName,
                    Moltiplicatore = req.Moltiplicatore,
                    SecondiRimanenti = req.SecondiRimanenti,
                    Data = DateTime.Now,
                };
                var PunteggioInserito = Db.Punteggi.Add(punt);
                Db.SaveChanges();

                TipologiaTest test = Db.TipologiaTest.Where(x => x.IdTipologiaTest == req.IdTipologiaTest).Single();

                test.PartiteRegistrate = ++test.PartiteRegistrate;

                Db.SaveChanges();

                var esito = new SetPunteggioResponse();
                if (Db.Punteggi.Where(x => x.IdTipologiaTest == punt.IdTipologiaTest && x.IdDifficolta == punt.IdDifficolta).OrderByDescending(x => x.Punteggio).Take(10).ToList().Contains(PunteggioInserito))
                    esito.isClassifica = true;

                esito.PunteggioAggiornato = new PunteggioService()
                {
                    IdDifficolta = (int)PunteggioInserito.IdDifficolta,
                    IdPunteggio = PunteggioInserito.IdPunteggio,
                    IdTipologiaTest = (int)PunteggioInserito.IdTipologiaTest,
                    Punteggio = (long)PunteggioInserito.Punteggio,
                    SecondiRimanenti = (int)PunteggioInserito.SecondiRimanenti,
                };
                return esito;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        /// <summary>
        /// Metodo di inserimento proposta domanda
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public InsertNuovaDomandaResponse InsertNuovaDomanda(InsertNuovaDomandaRequest request)
        {
            var Response = new InsertNuovaDomandaResponse();
            try
            {
                Response.EsitoInserimento = false;

                CreateDBConnetion();
                var domanda = new Domande()
                {
                    Domanda = request.Domanda.Domanda,
                    IdTipologiaTest = request.Domanda.IdTipologiaTest,
                    idCount = 0,
                    Version = Db.Version.First().IDVersion,
                    isVisibile = false,
                };
                domanda.PossibiliRisposte = (from elemento in request.Domanda.PossibiliRisposte
                                             select new PossibiliRisposte()
                                             {
                                                 DescrizioneRisposta = elemento.DescrizioneRisposta,
                                                 IsCorretta = elemento.IsCorretta,
                                             }).ToArray();

                Db.Domande.Add(domanda);
                Db.SaveChanges();
                Response.EsitoInserimento = true;
            }
            catch (Exception ex)
            {

                Response.EsitoInserimento = false;
            }
            return Response;

        }

        public GetTipologieAndDifficoltaResponse GetTipologieAndDifficoltaPhone(GetTipologieAndDifficoltaRequest request)
        {
            CreateDBConnetion();

            var response = new GetTipologieAndDifficoltaResponse();

            var listDiff = Db.Difficolta.OrderBy(x => x.IDDifficolta);
            response.ListDifficolta =
                (from elemento in listDiff
                 select new DifficoltaService()
                 {
                     IDDifficolta = elemento.IDDifficolta,
                     NumMaxDomande = elemento.NumMaxDomande,
                     TempoMaxDomande = elemento.TempoMaxDomande,
                     Punteggio = elemento.Punteggio,
                     Titolo = elemento.Titolo,
                 }).ToArray();


            var listTip = Db.TipologiaTest.OrderBy(x => x.Descrizione);

            response.ListTipologie =
            (from elemento in listTip
             select new TipologiaTestService()
             {
                 Descrizione = elemento.Descrizione,
                 DataCreazione = elemento.DataCreazione,
                 IdTipologiaTest = elemento.IdTipologiaTest,
                 Aggiornamenti = Db.Domande.Any(x => x.IdTipologiaTest == elemento.IdTipologiaTest && x.Version > request.Version)
             }).ToArray();

            response.UpdateDifficolta = Db.Difficolta.Where(x => x.Versione > request.Version).Count();
            response.UpdateDomande = Db.Domande.Where(x => x.Version > request.Version).Count();
            response.UpdateTipologie = Db.TipologiaTest.Where(x => x.Version > request.Version).Count();
            response.Version = Db.Version.Single().IDVersion;
            response.InfoBacheca = Db.Bacheca.Single().Informativa;

            return response;

        }


        /// <summary>
        /// Metodo che elabora costruisce un questionario in relazione alla tipologia di test e alla difficoltà
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public GetAllQuestionarioResponse GetAllQuestionarioPhone(GetAllQuestionarioRequest request)
        {
            try
            {
                CreateDBConnetion();
                var Dif = Db.Difficolta.Where(x => x.IDDifficolta == request.IdDifficolta).Single();
                var filtrolista = Db.Domande.Where(x => x.IdTipologiaTest == request.idTipologiaTest && x.isVisibile == true).ToList();
                var listaDomande = (from elemento in Filtro<Domande>.FiltraDifficolta(filtrolista, Dif.NumMaxDomande)
                                    select new DomandaService()
                                    {
                                        Domanda = elemento.Domanda,
                                        IdDomanda = elemento.IdDomanda,
                                        IdTipologiaTest = elemento.IdTipologiaTest,
                                        PossibiliRisposte =
                                        (from posRisp in Filtro<PossibiliRisposte>.FiltraAndMescolaRisposte(elemento.PossibiliRisposte.ToList(), elemento.PossibiliRisposte.Count())
                                         select new PossibiliRisposteService()
                                         {
                                             DescrizioneRisposta = posRisp.DescrizioneRisposta,
                                             IdDomanda = posRisp.IdDomanda,
                                             IdPossibileRisposta = posRisp.IdPossibileRisposta,
                                             IsCorretta = posRisp.IsCorretta
                                         }).ToArray()

                                    }).ToArray();

                foreach (var domanda in listaDomande)
                {
                    var dom = Db.Domande.Where(x => x.IdDomanda == domanda.IdDomanda).Single();
                    dom.idCount = dom.idCount + 1;
                }
                Db.SaveChanges();


                var response = new GetAllQuestionarioResponse();
                response.Difficolta = new DifficoltaService()
                {
                    IDDifficolta = Dif.IDDifficolta,
                    NumMaxDomande = Dif.NumMaxDomande,
                    TempoMaxDomande = Dif.TempoMaxDomande,
                    Titolo = Dif.Titolo
                };
                response.Questionario.ListaDomande = listaDomande;
                response.Questionario.NomeQuestionario = Db.TipologiaTest.Where(x => x.IdTipologiaTest == request.idTipologiaTest).Single().Descrizione;
                return response;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Metodo di inserimento Punteggio per il servizio Phone
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public SetPunteggioResponse SetPunteggioPhone(SetPunteggioNewRequest request)
        {
            SetPunteggioResponse esito = new SetPunteggioResponse();
            try
            {
                PunteggioService req = request.Request;
                if (req.UserName == "")
                    req.UserName = "Utente Non Registrato";
                CreateDBConnetion();
                var punt = new PunteggiPhone()
                {
                    IdDifficolta = req.IdDifficolta,
                    IdTipologiaTest = req.IdTipologiaTest,
                    Punteggio = req.Punteggio,
                    Account = req.UserName,
                    Moltiplicatore = req.Moltiplicatore,
                    //    SecondiRimanenti = req.SecondiRimanenti,
                    Data = DateTime.Now,
                };
                var PunteggioInserito = Db.PunteggiPhone.Add(punt);
                Db.SaveChanges();

                var test = Db.TipologiaTest.Where(x => x.IdTipologiaTest == req.IdTipologiaTest).Single();

                test.PartiteRegistrate = ++test.PartiteRegistrate;

                Db.SaveChanges();


                if (Db.PunteggiPhone.Where(x => x.IdTipologiaTest == punt.IdTipologiaTest && x.IdDifficolta == punt.IdDifficolta).OrderByDescending(x => x.Punteggio).Take(50).ToList().Contains(PunteggioInserito))
                    esito.isClassifica = true;

                esito.PunteggioAggiornato = new PunteggioService()
                {
                    IdDifficolta = (int)PunteggioInserito.IdDifficolta,
                    IdPunteggio = PunteggioInserito.IdPunteggioPhone,
                    IdTipologiaTest = (int)PunteggioInserito.IdTipologiaTest,
                    Punteggio = (long)PunteggioInserito.Punteggio,
                    //    SecondiRimanenti = (int)PunteggioInserito.SecondiRimanenti,
                };

            }
            catch (Exception ex)
            {
                esito.isClassifica = false;
                return esito;
            }
            return esito;
        }

        /// <summary>
        /// Metodo che permette di recuperare i migliori punteggi per tipologie
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public GetAllListPunteggiResponse GetAllListPunteggiPhone(GetListPunteggioRequest request)
        {
            try
            {
                CreateDBConnetion();
                var listaTipologie = Db.TipologiaTest.OrderBy(x => x.Descrizione).ToList();
                List<GetListPunteggioResponse> listAllPunteggi = new List<GetListPunteggioResponse>();
                foreach (var singleTipologia in listaTipologie)
                {
                    var ListElement = Db.PunteggiPhone.Where(x => x.IdTipologiaTest == singleTipologia.IdTipologiaTest).OrderByDescending(x => x.Punteggio).Take(50).ToList();
                    var esito = new GetListPunteggioResponse()
                    {
                        ListPunteggi =
                        (from p in ListElement
                         select new PunteggioService()
                         {
                             Index = ListElement.IndexOf(p) + 1,
                             IdDifficolta = (int)p.IdDifficolta,
                             IdPunteggio = p.IdPunteggioPhone,
                             IdTipologiaTest = (int)p.IdTipologiaTest,
                             Punteggio = (long)p.Punteggio,
                             UserName = p.Account,
                             TipologiaTest = p.TipologiaTest.Descrizione,
                             //          SecondiRimanenti = (int)p.SecondiRimanenti,
                             Moltiplicatore = p.Moltiplicatore
                         }).ToArray()
                    };
                    listAllPunteggi.Add(esito);
                }
                return new GetAllListPunteggiResponse() { ListAllPunteggi = listAllPunteggi.ToArray() };
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        #endregion

    }
}
